package cn.zhqr.core.service;

import cn.zhqr.common.bean.response.OutResponse;
import cn.zhqr.common.config.GlobalConstants;
import com.jfinal.ext.plugin.tx.DbTx;
import com.jfinal.ext.plugin.tx.Tx;
import com.jfinal.plugin.activerecord.Record;
import org.apache.log4j.Logger;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;

/**
 * 订单分账服务
 */
public class OrderSplitService {
    public static final OrderSplitService instance = new OrderSplitService();
    private static final Logger logger = Logger.getLogger(OrderSplitService.class);

    /**
     * 充值后预分账
     * @param payOrder
     */
    public void addOrderSplitTask(PayOrder payOrder){
        OrderSplit orderSplit = new OrderSplit();
        orderSplit.setType(OrderSplit.TYPE_RECHARGE);
        orderSplit.setAgentId(payOrder.getAgentId());
        orderSplit.setUserId(payOrder.getUserId());
        orderSplit.setStationId(payOrder.getStationId());
        orderSplit.setOriOrderNo(payOrder.getOrderNo());

        StationSetting stationSetting = StationSetting.dao.findByStationId(payOrder.getStationId());
        if(stationSetting == null){
            logger.error("addOrderSplitTask error: stationSetting is null or adv_split_percent is valid");
            return;
        }
        if(stationSetting.getAdvSplitPercent().compareTo(BigDecimal.ZERO) < 0 || stationSetting.getAdvSplitPercent().compareTo(GlobalConstants.HUNDRED) > 0){
            logger.error("addOrderSplitTask : adv_split_percent is invalid");
            return;
        }
        if(stationSetting.getAdvSplitPercent().compareTo(BigDecimal.ZERO) == 0){
            return;
        }

        BigDecimal amount = payOrder.getOrderAmount()
                .subtract(payOrder.getSplitAmount())
                .multiply(stationSetting.getAdvSplitPercent())
                .divide(GlobalConstants.HUNDRED,4,GlobalConstants.DEFAULT_ROUNDING_MODE);
        if(amount.compareTo(BigDecimal.ZERO) <= 0){
            logger.error("addOrderSplitTask split amount  is zero ,ignore to split");
            return;
        }

        orderSplit.setAmount(amount);
        orderSplit.setStatus(OrderSplit.STATUS_WAITING);
        orderSplit.setCreateTime(new Date());
        orderSplit.save();
    }


    /**
     * 消费后分账
     * @param userOrder
     */
    public void addOrderSplitTask(UserOrder userOrder){
        OrderSplit orderSplit = new OrderSplit();
        orderSplit.setType(OrderSplit.TYPE_CONSUME);
        orderSplit.setAgentId(userOrder.getAgentId());
        orderSplit.setUserId(userOrder.getUserId());
        orderSplit.setStationId(userOrder.getStationId());
        orderSplit.setRelationNo(userOrder.getOrderNo());

        StationSetting stationSetting = StationSetting.dao.findByStationId(userOrder.getStationId());
        if(stationSetting == null){
            logger.error("addOrderSplitTask error: stationSetting is null or adv_split_percent is valid");
            return;
        }
        if(stationSetting.getAdvSplitPercent().compareTo(BigDecimal.ZERO) < 0
                || stationSetting.getAdvSplitPercent().compareTo(GlobalConstants.HUNDRED) > 0){
            logger.error("addOrderSplitTask : adv_split_percent is invalid");
            return;
        }
        //如果是100%充值分账，则不进行消费分账。
        //存在问题：如果充值分账未完全分完，后改为100%充值分账，后续不会再分账。
        if(stationSetting.getAdvSplitPercent().compareTo(GlobalConstants.HUNDRED) == 0){
            logger.info("addOrderSplitTask : adv_split_percent is invalid");
            return;
        }

        UserWashCard userWashCard = UserWashCard.dao.findById(userOrder.getGoodsId());
        if(userWashCard == null || userWashCard.getPayOrderNo().compareTo(BigInteger.ZERO)==0){
            logger.error("addOrderSplitTask : userWashCard is null or pay_order_no is zero");
            return;
        }
        PayOrder payOrder = PayOrder.dao.findByOrderNo(userWashCard.getPayOrderNo());
        if(payOrder == null){
            logger.error("addOrderSplitTask : pay order is null,ignore to split");
            return;
        }

        orderSplit.setOriOrderNo(payOrder.getOrderNo());
        BigDecimal orderAmount = payOrder.getOrderAmount().subtract(payOrder.getSplitAmount()).min(userOrder.getOrderAmount());
        BigDecimal splitAmount = orderAmount
                .multiply(GlobalConstants.HUNDRED.subtract(stationSetting.getAdvSplitPercent()))
                .divide(GlobalConstants.HUNDRED,4,GlobalConstants.DEFAULT_ROUNDING_MODE);

        if(splitAmount.compareTo(BigDecimal.ZERO) <= 0){
            logger.error("addOrderSplitTask split amount  is zero ,ignore to split");
            return;
        }

        orderSplit.setAmount(splitAmount);
        orderSplit.setStatus(OrderSplit.STATUS_WAITING);
        orderSplit.setCreateTime(new Date());
        orderSplit.save();
    }

    /**
     * 充值后分账
     * @param orderSplit
     */
    public void splitOrder(OrderSplit orderSplit){
        if(orderSplit == null || orderSplit.getStatus() != OrderSplit.STATUS_WAITING){
            return;
        }

        if(orderSplit.getAmount().compareTo(BigDecimal.ZERO) == 0){
            splitFail(orderSplit,"金额小于或等于0，不分账");
            return;
        }
        if(orderSplit.getOriOrderNo()==null || orderSplit.getOriOrderNo().compareTo(BigInteger.ZERO) <= 0){
            splitFail(orderSplit,"原订单号为空");
            return;
        }
        PayOrder payOrder = PayOrder.dao.findByOrderNo(orderSplit.getOriOrderNo());
        if(payOrder == null){
            splitFail(orderSplit,"原订单不存在");
            return;
        }
        if(payOrder.getStationId() == null || payOrder.getStationId() == 0){
            splitFail(orderSplit,"原订单所属网点为空");
            return;
        }
        StationSetting stationSetting = StationSetting.dao.findByStationId(payOrder.getStationId());
        if(stationSetting == null){
            splitFail(orderSplit,"未查询到所属网点配置参数");
            return;
        }

        List<OrderSplitRule> splitList = OrderSplitRuleService.instance.getOrderSplitRules(payOrder.getStationId());
        OutResponse checkResult = OrderSplitRuleService.instance.checkSplitRules(splitList);
        if(!checkResult.isSuccess()){
            splitFail(orderSplit,checkResult.getMsg());
            return;
        }

        BigDecimal totalAmount = orderSplit.getAmount();

        DbTx.execute(new Tx() {
            @Override
            public void sql() {
                OrderSplit.dao.findAndLockById(orderSplit.getId());//加锁，防止重复结算

                if(orderSplit.getStatus() != OrderSplit.STATUS_WAITING){
                    return;
                }

                for(OrderSplitRule splitRule : splitList){
                    BigDecimal amount = totalAmount.multiply(splitRule.getPercent()).divide(GlobalConstants.HUNDRED,4,GlobalConstants.DEFAULT_ROUNDING_MODE);
                    BigDecimal fee = amount.multiply(stationSetting.getServiceFeeRate()).divide(GlobalConstants.HUNDRED,4,GlobalConstants.DEFAULT_ROUNDING_MODE);
                    BigDecimal splitAmount = amount.subtract(fee);

                    OrderSplitLog orderSplitLog = new OrderSplitLog();
                    orderSplitLog.setToAgentId(splitRule.getAgentId());
                    orderSplitLog.setStationId(splitRule.getStationId());
                    orderSplitLog.setOrderSplitId(orderSplit.getId());
                    orderSplitLog.setAmount(splitAmount);
                    orderSplitLog.setFee(fee);
                    orderSplitLog.setCreateTime(new Date());
                    orderSplitLog.save();
                }

                orderSplit.setAmount(totalAmount);
                orderSplit.setStatus(OrderSplit.STATUS_SUCCESS);
                orderSplit.setMsg("");
                orderSplit.setCompleteTime(new Date());
                orderSplit.update();

                if(totalAmount.compareTo(BigDecimal.ZERO) > 0){
                    PayOrder.dao.increaseSplitAmount(payOrder.getOrderNo(),orderSplit.getAmount());
                }
            }

            @Override
            public void error(Exception e) {
                logger.error("分账失败  ori_order_no:"+orderSplit.getOriOrderNo()+" ",e);
            }
        });
    }



    private void splitFail(OrderSplit orderSplit,String errMsg){
        orderSplit.setStatus(OrderSplit.STATUS_FAILED);
        orderSplit.setMsg(errMsg==null?"":errMsg);
        orderSplit.update();

        logger.error(" 分账失败 id:"+orderSplit.getId()+" "+errMsg);
    }


    public void mergePay(Long toAgentId,Long stationId,Date endTime,BigDecimal totalAmount,BigDecimal totalFee){
        mergePay(new Date(),toAgentId,stationId,endTime,totalAmount,totalFee);
    }
    /**
     * 合并付款
     * @param date
     * @param toAgentId
     * @param stationId
     * @param totalAmount
     * @param totalFee
     */
    public void mergePay(Date date,Long toAgentId,Long stationId,Date endTime,BigDecimal totalAmount,BigDecimal totalFee){
        if(totalAmount.abs().compareTo(GlobalConstants.MIN_MONEY) < 0){
            logger.info("金额过小，本次忽略 to_agent_id:"+toAgentId+" station_id:"+stationId+" total_amount:"+totalAmount);
            return;
        }
        BigDecimal finalAmount = totalAmount.setScale(2,GlobalConstants.DEFAULT_ROUNDING_MODE);

        Record record = OrderSplitLog.dao.statUnsettledByAgentIdAndStationId(toAgentId,stationId,endTime);

        BigDecimal confirmAmount = record.getBigDecimal("total_amount");
        BigDecimal confirmFee = record.getBigDecimal("total_fee");
        if(totalAmount.compareTo(confirmAmount)!=0 || totalFee.compareTo(confirmFee)!=0){
            logger.info("金额不一致，请检查 to_agent_id:"+toAgentId+" station_id:"+stationId+" total_amount:"+totalAmount+" total_fee"+totalFee+" confirm_amount:"+confirmAmount+" :confirm_fee"+confirmFee);
            return;
        }

        DbTx.execute(new Tx() {
            @Override
            public void sql() {
                AgentWallet.dao.increaseBalance(toAgentId,finalAmount);

                AgentTrade agentTrade = new AgentTrade();
                agentTrade.setTradeType(finalAmount.compareTo(BigDecimal.ZERO)>0?AgentTrade.TYPE_INCOME:AgentTrade.TYPE_OUTCOME);
                agentTrade.setStationId(stationId);
                agentTrade.setDesc(Station.dao.findNameById(stationId));
                agentTrade.setAgentId(toAgentId);
                agentTrade.setAmount(finalAmount);
                agentTrade.setBalance(AgentWallet.dao.findBalanceByAgentId(toAgentId));
                agentTrade.setCreateTime(date);
                agentTrade.setPayChannel(GlobalConstants.PAY_CHANNEL_SYSTEM);
                agentTrade.save();


                OrderSplitLog.dao.updateToPayed(date,agentTrade.getId(),toAgentId,stationId,endTime);
            }

            @Override
            public void error(Exception e) {
                logger.error("merge pay transaction error:",e);
            }
        });
    }
}
